package cn.lr.basic.service.impl;

import cn.lr.basic.Exception.BusinessException;
import cn.lr.basic.constant.BaseConstants;
import cn.lr.basic.dto.LoginDto;
import cn.lr.basic.jwt.JwtUtils;
import cn.lr.basic.jwt.RsaUtils;
import cn.lr.basic.jwt.UserInfo;
import cn.lr.basic.service.ILoginService;
import cn.lr.basic.util.AjaxResult;
import cn.lr.basic.util.HttpClientUtils;
import cn.lr.basic.util.MD5Utils;
import cn.lr.basic.util.StrUtils;
import cn.lr.system.domain.Menu;
import cn.lr.system.mapper.MenuMapper;
import cn.lr.system.mapper.PermissionMapper;
import cn.lr.user.domain.Logininfo;
import cn.lr.user.domain.User;
import cn.lr.user.domain.Wxuser;
import cn.lr.user.mapper.LogininfoMapper;
import cn.lr.user.mapper.UserMapper;
import cn.lr.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Value("${jwt.rsa.pri}")
    private String jwtRsaPrivate;

    /**
     * 账号密码登录
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> account(LoginDto dto) {
        // 参数校验
        if(StringUtils.isEmpty(dto.getUsername()) || StringUtils.isEmpty(dto.getPassword()) ||StringUtils.isEmpty(dto.getType())){
            throw new BusinessException("请填写完整信息后登录！！");
        }
        // 2.根据username+type查询logininfo表，同时匹配username phone email
        Logininfo logininfo = logininfoMapper.loadByUsernameAndLogininfo(dto.getUsername(),dto.getType());
        if(logininfo == null){
            throw new BusinessException("用户不存在");
        }
        // 比对密码
        // 获取盐值
        String salt = logininfo.getSalt();
        // 加密加盐
        String md5Pwd = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if(!md5Pwd.equals(logininfo.getPassword())){
            throw new BusinessException("用户或密码错误");
        }
//        // 获取UUID
//        String token = UUID.randomUUID().toString();
//        // 保存到redis，设置过期时间
//        redisTemplate.opsForValue().set(
//                token,
//                logininfo,
//                30,
//                TimeUnit.MINUTES);
//        // 返回token和logininfo给前端
//        Map<String, Object> map = new HashMap<>();
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("token",token);
//        map.put("logininfo",logininfo);
//        return map;
        return loginSuccessHandle(logininfo);

    }

    private Map<String, Object> loginSuccessHandle(Logininfo logininfo) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUser(logininfo); // 当前登录人
        if(logininfo.getType() == 1){ // 前端用户登录
            userInfo.setMenus(null);
            userInfo.setPermissions(null);
        } else { // 后端员工登录
            // 员工登录需要查询权限
            // 查询菜单权限
            List<Menu> menus = menuMapper.loadMenuByLogInfoId(logininfo.getId());
            // 查询按钮权限
            List<String> permissions = permissionMapper.loadPermissionByLoginInfoId(logininfo.getId());
            userInfo.setMenus(menus);
            userInfo.setPermissions(permissions);
        }
        try {
            // 获取私钥
            PrivateKey privateKey = RsaUtils
                    .getPrivateKey(FileCopyUtils
                            .copyToByteArray(this.getClass().getClassLoader().getResourceAsStream(jwtRsaPrivate)));
            // JWT串
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 30);
            // 将JWT串返回给前端
            Map<String, Object> map = new HashMap<>();
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("token",token);
        map.put("logininfo",logininfo);
        map.put("menus",userInfo.getMenus());
        map.put("permissions",userInfo.getPermissions());
        return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 微信扫码登录
     * @param param
     * @return
     */
    @Override
    public AjaxResult wechat(Map<String, String> param) {
        //        2.校验参数
        String code = param.get("code");
        if (StringUtils.isEmpty(code)) {
            throw new BusinessException("微信炸了");
        }
        // 3.根据code，拼接从微信获取token的请求
        String tokenUrl = BaseConstants.WechatConstants.TOKEN_URL
                .replace("APPID",BaseConstants.WechatConstants.APPID)
                .replace("SECRET",BaseConstants.WechatConstants.SECRET)
                .replace("CODE",code);
//        4.向微信发起获取token的请求，接收微信响应：access_token + openid
        String tokenJsonStr = HttpClientUtils.httpGet(tokenUrl);
        // 将json字符串转成JSON对象
        JSONObject tokenObj = JSONObject.parseObject(tokenJsonStr);
        String accessToken = tokenObj.getString("access_token");
        String openId = tokenObj.getString("openid");
        // 5.根据openid查询本地的t_wxuser表，判断是否已经存在用户
        Wxuser wxuser = wxuserMapper.loadByOpendId(openId);
        if(wxuser != null && wxuser.getId() != null){ // 存在此用户，直接免密登录
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
            // 获取UUID
//            String token = UUID.randomUUID().toString();
//            // 保存到redis，设置过期时间
//            redisTemplate.opsForValue().set(
//                    token,
//                    logininfo,
//                    30,
//                    TimeUnit.MINUTES);
//            // 返回token和logininfo给前端
//            Map<String, Object> map = new HashMap<>();
//            logininfo.setSalt(null);
//            logininfo.setPassword(null);
//            map.put("token",token);
//            map.put("logininfo",logininfo);
            Map<String, Object> map = loginSuccessHandle(logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        //  。不存在，让页面定位到微信绑定页面
        // 注意：需要携带access_token + openid回去
        String bindeParamStr = "?accessToken=" + accessToken + "&openId=" + openId;
        return AjaxResult.me().setSuccess(false).setResultObj(bindeParamStr);
    }
    /**
     * 微信绑定用户
     * @param param
     * @return
     */
    @Override
    public Map<String, Object> binder(Map<String, String> param) {
//        2.校验参数
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        if(StringUtils.isEmpty(phone)
                ||StringUtils.isEmpty(verifyCode)
                ||StringUtils.isEmpty(accessToken)
                ||StringUtils.isEmpty(openId)){
            throw new BusinessException("用户信息不能为空");
        }
        // 校验验证码是否过期
        String smsCodeKey = BaseConstants.VerifyCodeConstants.BUSINESS_BINDER_PREFIX + phone;
        Object smsCodeValueTemp = redisTemplate.opsForValue().get(smsCodeKey); // 验证码：时间戳
        if(smsCodeValueTemp == null){
            throw new BusinessException("验证码已过期，请重新获取");
        }
        String smsCode = smsCodeValueTemp.toString().split(":")[0]; // 验证码
        if(!smsCode.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("验证码错误");
        }
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        // 3.判断用户是否已经存在
        if(user == null){
            //   - 不存在，生成user + logininfo
            user  = initUser(phone);
            logininfo = user2logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);
        } else {
            //  - 存在 查询user
            logininfo = logininfoMapper.loadByUserId(user.getId());
        }
//        4.拼接获取微信微信用户信息的请求，调用微信去获取微信用户基本信息
        String wxuserUrl = BaseConstants.WechatConstants.WXUSER_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
//        5.微信响应结果
        String wxUserJsonStr = HttpClientUtils.httpGet(wxuserUrl);
        Wxuser wxuser = JSONObject.parseObject(wxUserJsonStr, Wxuser.class);
//        。绑定user
//        。保存t_wxuser
        wxuser.setUserId(user.getId());
        wxuserMapper.save(wxuser);
//        6.免密登录成功，跳到主页，显示用户信息
        // 获取UUID
//        String token = UUID.randomUUID().toString();
//        // 保存到redis，设置过期时间
//        redisTemplate.opsForValue().set(
//                token,
//                logininfo,
//                30,
//                TimeUnit.MINUTES);
//        // 返回token和logininfo给前端
//        Map<String, Object> map = new HashMap<>();
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("token",token);
//        map.put("logininfo",logininfo);
        return loginSuccessHandle(logininfo);
    }

    private Logininfo user2logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1); // 用于确定是员工登录还是用户登录
        return logininfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5("1" + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }
}
